/******************************************************************************
 * \brief	将ASCII字符串文本文件转成int类型的二进制文件并保存
 * \details	文本文件是用空格区分的4个字符的16进制ADC采样数据，转成符合PCM音频
 *			数据规范的二进制
 * \note	PCM文件中并不携带音频采样率、采样深度、通道数等信息，所以播放PCM文件
 *			时要手动指定采样率、采样深度、通道数信息
 * \remark	播放pcm的命令：ffplay -ar 8000 -ac 1 -f u16le -i out.pcm
 *			PCM格式：f/s/u 32/64/16/24/8 be/le
 *			采样率：8000 11025 22050 24000 44100 48000
 * \author	将狼才鲸
 * \date	2023-02-16
 ******************************************************************************/

#include <stdio.h>	/* fopen fread fwrite ftell fclose */
#include <string.h>	/* printf strtok */
#include <stdlib.h>	/* atoi */

#define INFILE_NAME		"in.txt"
#define OUTFILE_NAME	"out.pcm"
#define MAX_CACHE_SIZE	(16 * 1024 * 1024)	/* 一次性缓存16M大小的文件内容 */
//#define USE_12BIT_TO_16BIT

static char inbuf[MAX_CACHE_SIZE];
static int indata_len;

/* 这是PC上将串口字符串转成PCM文件的主程序 */
int main(int argc, char *argv[])
{
	FILE *fpin, *fpout;
	char *finname = INFILE_NAME;
	char *foutname = OUTFILE_NAME;
	int infile_len;

	printf("use './txt2pcm.exe yourfilename.txt' in cmd window\n");

	if (argc > 1)
		finname = argv[1];

	printf("filename is %s\n", finname);
	
	/* 1. 打开输入输出文件 */
	fpin = fopen(finname, "r");	/* 只读 */
	if (NULL == fpin) {
		printf("open %s fail!\n", finname);
		goto exit;
	}
	fpout = fopen(foutname, "wb");	/* 二进制模式只写，文件存在则新建 */
	if (NULL == fpout) {
		printf("open %s fail!\n", foutname);
		goto exit1;
	}
	
	/* 2. 获取输入文件长度 */
	fseek(fpin, 0, SEEK_END);	/* 指向文件末尾 */
	infile_len = ftell(fpin);	/* 获取当前位置的总长度 */
	fseek(fpin, 0, SEEK_SET);	/* 重新定位到文件开头 */
	
	if (infile_len > MAX_CACHE_SIZE) {
		printf("the file len %d is large than buffer size %d!\n", infile_len, MAX_CACHE_SIZE);
		infile_len = MAX_CACHE_SIZE;
	}
	
	/* 3. 读取文件内容 */
	int rlen = fread(inbuf, sizeof(char), infile_len, fpin);
	if (rlen != infile_len) {
		printf("the len %d of read is not equal to file len %d!\n", rlen, infile_len);
		goto exit2;
	}
	
	/* 4. 将文件内容切割并转成unsigned int类型 */
	char *rstr = strtok(inbuf, " ");	/* 按空格分割字符串，第一次拆分传inbuf参数，以后的拆分都传NULL */
	unsigned short point;	/* 16bit采样深度 */
	unsigned int tmp;
	if (rstr) {
		tmp = atoi(rstr);
#ifdef USE_12BIT_TO_16BIT
		/* 12bit到16bit采样深度的转换，4096与65536，point/4096=x/65536 */
		tmp = tmp * 65536 / 4096;
#endif
		//printf("%u ", tmp);
		point = tmp;
		fwrite(&point, sizeof(unsigned short), 1, fpout);	/* Windows和Linux都是默认小端模式 */
	}
	while (NULL != rstr) {
		rstr = strtok(NULL, " ");	/* strtok函数带记忆功能，知道你前一次操作的字符串地址 */
		if (rstr) {
			tmp = atoi(rstr);
#ifdef USE_12BIT_TO_16BIT
			tmp = tmp * 65536 / 4096;
#endif
			//printf("%u ", tmp);
			point = tmp;
			fwrite(&point, sizeof(unsigned short), 1, fpout);
		}
	}

	printf("...\nfinish and exit\n");

exit2:
	fclose(fpout);
	
exit1:
	fclose(fpin);

exit:
	fflush(stdout);
	while (1);
	return 0;
}